﻿/*
 * PsTFS is a set of PowerShell commands to manage and use Team Foundation Server. PowerShell 
 * effectiveness is combined with the power of TFS API to maximizes TFS capabilities.
 * 
 * Creator : Choulant Noham
 * Mail : choulant@gmail.com
 * Blog : http://choulant.blogspot.com
 * 
 */

using System;
using System.ComponentModel;
using System.Management.Automation;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Configuration.Install;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.VersionControl.Client;
using System.Linq;
using System.IO;
using PowerShell.Host.PsTFS.CdmLet.PsObject;
using Microsoft.TeamFoundation.WorkItemTracking.Client;

namespace PowerShell.Host.PsTFS.CdmLet
{
    /// <summary>
    /// Fusion entre deux branches
    /// </summary>
    [Cmdlet(VerbsCommon.Set, "Merge")]
    public class Set_Merge : Cmdlet
    {
        public Set_Merge()
        {
            if (TFSProvider.s_TFSDriveInfo != null)
            {
                this.TFS = TFSProvider.s_TFSDriveInfo.TFS;
                this.ProjectName = TFSProvider.s_TFSDriveInfo.ProjectName;
            }
        }
            
        List<Changeset> listReturn = new List<Changeset>();

        protected override void ProcessRecord()
        {
            Workspace workspace = null;
            try
            {
                // Get a reference to Version Control. 
                VersionControlServer versionControl = PsService.VCS(TFS);

                // Create a workspace. 
                workspace = versionControl.CreateWorkspace(Guid.NewGuid().ToString(), versionControl.AuthenticatedUser);

                try
                {
                    var _s = Environment.GetFolderPath(Environment.SpecialFolder.InternetCache) + @"\tempPsTFS\" + Guid.NewGuid().ToString() + @"\Source";
                    var _t = Environment.GetFolderPath(Environment.SpecialFolder.InternetCache) + @"\tempPsTFS\" + Guid.NewGuid().ToString() + @"\Target";
                    // Create a mapping using the Team Project supplied on the command line. 
                    workspace.Map(Source, _s);
                    workspace.Map(Target, _t);

                    // Get the files from the repository. 
                    workspace.Get();
                    if (this.ChangeSet != null)
                    {
                        this.ChangeSet = this.ChangeSet.OrderBy(cs => cs.ChangesetId).ToList();

                        foreach (Changeset cs in this.ChangeSet)
                        {
                            Merge(workspace, cs);
                        }
                    }
                    if (this.Workitem != null)
                    {
                        List<Changeset> listCS = new List<Changeset>();

                        foreach (WorkItem w in this.Workitem)
                        {
                            foreach (Changeset cs in w.ListChangeset())
                            {
                                bool trouve = false;
                                foreach (Changeset c in listCS)
                                {
                                    if (c.ChangesetId == cs.ChangesetId)
                                    {
                                        trouve = true;
                                    }
                                }
                                if (!trouve)
                                {
                                    listCS.Add(cs);
                                }
                            }
                        }

                        listCS = listCS.OrderBy(cs => cs.ChangesetId).ToList();

                        foreach (Changeset cs in listCS)
                        {
                            Merge(workspace, cs);
                        }
                    }
                    else
                    {
                        GetStatus status = workspace.Merge(Source,
                            Target,
                            null,
                            null,
                            LockLevel.None,
                            RecursionType,
                            MergeOptions);

                        Console.WriteLine("Number conflicts : " + status.NumConflicts.ToString());
                        Console.WriteLine("Number failures : " + status.NumFailures.ToString());
                        Console.WriteLine("Number operations : " + status.NumOperations.ToString());
                        Console.WriteLine("Number warnings : " + status.NumWarnings.ToString());

                        PsLog.AddLog("Number conflicts : " + status.NumConflicts.ToString());
                        PsLog.AddLog("Number failures : " + status.NumFailures.ToString());
                        PsLog.AddLog("Number operations : " + status.NumOperations.ToString());
                        PsLog.AddLog("Number warnings : " + status.NumWarnings.ToString());

                        WriteObject(status.GetFailures(), true);


                        Pending(workspace);
                    }

                }
                finally
                {
                    if (workspace != null)
                    {
                        // Delete the workspace. 
                        bool delete = workspace.Delete();
                    }
                }
            }
            catch (Exception ex)
            {
                ErrorRecord err = new ErrorRecord(ex, "<ID>", ErrorCategory.WriteError, null);
                WriteError(err);
                PsLog.AddLog(null, ex.StackTrace);
            }
            finally
            {
                if (workspace != null && !workspace.IsDeleted)
                {
                    // Delete the workspace. 

                    workspace.Delete();
                }
            }
            WriteObject(listReturn);

        }

        private void Merge(Workspace workspace, Changeset cs)
        {
            VersionSpec version = VersionSpec.ParseSingleSpec(cs.ChangesetId.ToString(), TFS.AuthenticatedUserName);
            

            GetStatus status = workspace.Merge(Source,
            Target,
            version,
            version,
            LockLevel.None,
            RecursionType,
            MergeOptions);

            Console.WriteLine("");
            Console.WriteLine("Changeset n° : " + cs.ChangesetId.ToString());
            Console.WriteLine("---------------------------------");
            Console.WriteLine("Number conflicts : " + status.NumConflicts.ToString());
            Console.WriteLine("Number failures : " + status.NumFailures.ToString());
            Console.WriteLine("Number operations : " + status.NumOperations.ToString());
            Console.WriteLine("Number warnings : " + status.NumWarnings.ToString());

            PsLog.AddLog("Changeset n° : " + cs.ChangesetId.ToString());
            PsLog.AddLog("Number conflicts : " + status.NumConflicts.ToString());
            PsLog.AddLog("Number failures : " + status.NumFailures.ToString());
            PsLog.AddLog("Number operations : " + status.NumOperations.ToString());
            PsLog.AddLog("Number warnings : " + status.NumWarnings.ToString());

            WriteObject(status.GetFailures(), true);


            Pending(workspace);
        }

        private void Pending(Workspace workspace)
        {

            Conflict[] conflicts = workspace.QueryConflicts(new string[] { Target }, true);

            foreach (Conflict conflict in conflicts)
            {
                if (workspace.MergeContent(conflict, true))
                {
                    conflict.Resolution = Resolution.AcceptMerge;
                    workspace.ResolveConflict(conflict);
                }
                if (conflict.IsResolved)
                {
                    workspace.PendEdit(conflict.TargetLocalItem);
                    //File.Copy(conflict.MergedFileName, conflict.TargetLocalItem,
                     //   true);
                }
            }


            // Show our pending changes. 
            PendingChange[] pendingChanges = workspace.GetPendingChanges();

            PsLog.AddLog(null, "Your current pending changes:");

            if (pendingChanges.Length > 0)
            {
                foreach (PendingChange pendingChange in pendingChanges)
                {
                    PsLog.AddLog(null, "  path: " + pendingChange.LocalItem +
                                      ", change: " + PendingChange.GetLocalizedStringForChangeType(pendingChange.ChangeType));
                }

                // Checkin the items we added. 
                int changesetNumber = workspace.CheckIn(pendingChanges, Description);

                PsLog.AddLog(null, "Checked in changeset " + changesetNumber);

                listReturn.Add(workspace.VersionControlServer.GetChangeset(changesetNumber));
            }
            else
            {
                PsLog.AddLog(null, "Not changeset");

            }
        }
        /// <summary>
        /// Permet de récupérer la fin de la commande
        /// </summary>
        protected override void EndProcessing()
        {
            PsLog.AddLog(null, "Set-Merge is end");
            base.EndProcessing();
        }

        [Parameter(Position = 0)]
        public TeamFoundationServer TFS { get; set; }

        [Parameter(Position = 1)]
        public string ProjectName { get; set; }

        [Parameter(Position = 2, Mandatory = true)]
        [ValidateNotNullOrEmpty]
        public string Source { get; set; }

        [Parameter(Position = 3, Mandatory = true)]
        [ValidateNotNullOrEmpty]
        public string Target { get; set; }

        [Parameter(Position = 4, Mandatory = true)]
        [ValidateNotNullOrEmpty]
        public string Description { get; set; }

        [Parameter(Position = 5, Mandatory = true)]
        [ValidateNotNullOrEmpty]
        public RecursionType RecursionType { get; set; }

        [Parameter(Position = 6, Mandatory = true)]
        [ValidateNotNullOrEmpty]
        public MergeOptions MergeOptions { get; set; }

        [Parameter(Position = 7)]
        [ValidateNotNullOrEmpty]
        public List<WorkItem> Workitem { get; set; }

        [Parameter(Position = 8)]
        [ValidateNotNullOrEmpty]
        public List<Changeset> ChangeSet { get; set; }
    }
}
